﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace System.Linq
{
    public static class DbSetExt
    {
        private static Expression ExpTrue = Expression.Constant(true);

        public static long EmptyEnumValue => long.MinValue;

        /// <summary>
        /// where方法扩展
        /// </summary>
        /// <typeparam name="TSource"></typeparam>
        /// <typeparam name="TParam"></typeparam>
        /// <param name="source">实体</param>
        /// <param name="param">查询模型</param>
        /// <returns></returns>
        public static IQueryable<TSource> Where<TSource, TParam>(this IQueryable<TSource> source, TParam param)
        {
            var expression = Where<TSource, TParam>(param);
            var expression2 = Expression.Call(null, GetMethodInfo(Queryable.Where, source, expression), new Expression[2]
            {
                source.Expression,
                Expression.Quote(expression)
            });
            return source.Provider.CreateQuery<TSource>(expression2);
        }

        /// <summary>
        /// </summary>
        /// <typeparam name="TSource"></typeparam>
        /// <typeparam name="TParam"></typeparam>
        /// <param name="ht"></param>
        /// <returns></returns>
        public static Expression<Func<TSource, bool>> Where<TSource, TParam>(TParam ht)
        {
            var list = new List<Expression>();
            var modelExpression = ModelExpression.Instance<TSource>();
            foreach (var paramItem in ParamModel.Instance<TParam>().List)
            {
                var expressionItem = modelExpression.ExpList.FirstOrDefault(a => paramItem.MatchName.Equals(a.Prop.Name));
                if (expressionItem != null)
                {
                    var expression = BuildExp(expressionItem, paramItem, ht);
                    if (expression != null)
                    {
                        list.Add(expression);
                    }
                }
            }

            if (!list.Any())
                list.Add(ExpTrue);

            Expression expression2 = list[0];
            for (int i = 1; i < list.Count; i++)
            {
                expression2 = Expression.AndAlso(expression2, list[i]);
            }
            return Expression.Lambda<Func<TSource, bool>>(expression2, new ParameterExpression[1]
            {
                modelExpression.ParamName
            });
        }

        private static MethodInfo GetMethodInfo<T1, T2, T3>(Func<T1, T2, T3> f, T1 unused1, T2 unused2)
        {
            return f.Method;
        }

        private static Expression BuildExp(ModelExpression.ExpressionItem modelItem, ParamItem paramItem, object param)
        {
            return Ext.BuilderList.FirstOrDefault(a => a.OpType == paramItem.OpType)?.BuildExp(modelItem, paramItem, param);
        }
    }
}